by Kenn Scribner
In This Chapter
If there is one area where mixing MFC and COM is truly exciting (there are many), it has to be in adding scripting capability to your MFC application. Many MFC applications exist, as do many COM objects. Many MFC applications use COM objects. But few applications you find, except those coming from Microsoft, truly give you the ability to customize and automate their use through scripting. Frankly, many people Ive talked with find this topic very mysterious. Yet it is one of the more interesting.
What is so exciting about scripting is the manner in which the application (MFC) and the COM objects work together in more than just a simple client/server relationship. To be truly useful, the COM object needs to be a part of the application yet still satisfy the requirements of COM. This can be challenging to implement.
In this chapter, I show you how to add scripting capabilities to your application. My techniques are not the only way this can be done, but I have found these techniques to be as faithful to COM as is possible yet still allow the COM objects to expose information private to the application. Ill start with some basic concepts.
When I use the term scripting, I truly mean anointing your application with the capability to parse and execute VBScript or JScript code designed to access portions of your application. Perhaps your script will change the size of the applications window. Or just as likely, your script might be designed to take some action after the applications document has been modified (I refer to this state as dirty). You might also want a script available to quit the application when a predetermined set of criteria is met.
Your goal, as the application designer, is to think like your users and provide them with the best possible automation tools your application can provide. By this I mean that you begin your scripting architectural design process by laying out an object model for your application (Ill cover this in more detail later in the chapter). When your users write a script for your application, they will be accessing objects your application exposes. The trick is to understand your applications problem domain well and design an object model that best fits that problem domain.
Any objects your application exposes will have certain requirements levied upon them due to the nature of the Microsoft scripting architecture, which inherits its needs from Visual Basic. After all, VBScript is a language subset of Visual Basic. Microsoft used the same technology when it implemented Visual J++ and its scripting language subset JScript. To be sure you have an understanding of these architectural requirements, Ill detail them later in this section.
Note:Throughout the remainder of this chapter, I will refer primarily to VBScript. This isnt to neglect JScript, but rather to simplify the conceptual descriptions by referring solely to a single scripting language. When it comes to ActiveX scripting, either language is interchangeable from a scripting engine perspective.
Adding scripting capability to your MFC application requires you to provide scripting functionality in three major areas:
Fortunately, you need only concentrate on the first two areas. Microsoft has provided the third free of charge, although you do have to license the technology and acknowledge Microsoft in your application. As an MFC programmer you already manage the first task, so the only added work on your part is to design the applications object model and write the code to support the objects themselves. Ill begin my detailed description of the scripting process by describing the piece Microsoft provides.
When you add scripting capability to your MFC application, you have several alternatives. First, you might design a completely proprietary scripting language and the tools that go with it (runtime environment, parsing, execution, and so on). Second, you might fake a scripting environment by providing some customization and pseudo-executable commands that might appear to be script-like. Of course, you could purchase a third-party package that provides most of the tools you need. But the alternative I find most attractive is using freely available scripting technology. Im referring to the ActiveX Scripting engine provided by Microsoft.
Microsoft makes scripting available to you, the application programmer, by providing several COM objects and interfaces. If you know something about the scripting libraries and the COM interfaces, and if you have the compiler tools to support it (header files and such things), you can add scripting functionality to your application by invoking COM and using the scripting objects already available. And best of all, theyre free. Therefore, incorporating the ActiveX Scripting engine into your application is what this chapter really explores.
Microsoft ActiveX Scripting
The scripting technology youll use in this chapter is called Microsoft ActiveX Scripting. This technology provides you with the scripting runtime environment, a small set of development files, and a brief text file describing what is included in the download you will receive when you agree to the online licensing agreement (more on this later). The primary language files are VBScript.dll and JScript.dll, and the scripting runtime is provided by scrrun.dll. Each of these files is a COM in-process server DLL.
These DLLs collectively expose many COM interfaces, and describing them all is well beyond the scope of this chapter. However, the good news is that there are only a few you need to understand to provide basic scripting services. Microsoft has provided what I consider the four main scripting engine interfaces: IActiveScript, IActiveScriptParse, IActiveScriptSite, and IActiveScriptSiteWindow, and these are the four scripting interfaces Ill deal with in this chapter. There are additional ActiveX scripting interfaces you might find interesting, so be sure to refer to the online documentation for more details.
The IActiveScript interface is used to initialize and control the scripting engine. For example, you add scripted objects from your object model using IActiveScript::AddNmedItem(). Or you terminate the engine and any running script using IActiveScript::Close().